﻿/************************************************************************************
 * xujiajun@yoozoo.com 御剑
 * 平移操作相关的工具类
 ***********************************************************************************/

using UnityEngine;

public static class TranslationUtility
{
	/// <summary>
	/// 计算源世界坐标沿XZ平面平移到指定屏幕位置投影的新世界坐标
	/// </summary>
	/// <param name="cam">屏幕摄像机位置</param>
	/// <param name="worldPos">世界坐标</param>
	/// <param name="screenPos">屏幕位置</param>
	/// <returns>平移后的世界坐标，该坐标与worldPos在同一平面，并且投影到屏幕坐标的值为screenPos</returns>
	public static Vector3 TranslateXZByScreenPos(UnityEngine.Camera cam, Vector3 worldPos, Vector3 screenPos)
	{
		// 求出直线和平面的交点
		// 设为P为要求出的目标点，P0为平面上的点（即原世界坐标），n为平面的法线（垂直朝上的法线），L0为直线上的点（摄像机位置），d为直线上点到平面的距离，L为直线上点到平面的单位方向
		// 公式1 ( P - P0 )·n = 0	根据平面上两点求出的向量必定和平面法线的点乘为0
		// 公式2 P = L0 + dL	目标点为直线上的点加上直线的点到平面的距离乘以直线上点到平面的单位方向
		// 公式2代入公式1 d = ( ( P0 - L0 ) · n ) / ( L · n )
		// d代入公式2求出P
		var P0 = worldPos;
		var n = Vector3.up;
		var L0 = cam.transform.position;
		var z = cam.worldToCameraMatrix.MultiplyPoint(worldPos).z;
		screenPos.z = z;
		var L = (cam.ScreenToWorldPoint(screenPos) - L0).normalized;
		var d = Vector3.Dot((P0 - L0), n) / (Vector3.Dot(L, n));
		var P = L0 + d * L;

		return P;
	}
}
